package com.example.yyg.springframework.beans.factory.xml;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import com.example.yyg.springframework.beans.BeansException;
import com.example.yyg.springframework.beans.PropertyValue;
import com.example.yyg.springframework.beans.PropertyValues;
import com.example.yyg.springframework.beans.factory.config.BeanDefinition;
import com.example.yyg.springframework.beans.factory.config.BeanReference;
import com.example.yyg.springframework.beans.factory.support.AbstractBeanDefinitionReader;
import com.example.yyg.springframework.beans.factory.support.BeanDefinitionRegistry;
import com.example.yyg.springframework.core.io.Resource;
import com.example.yyg.springframework.core.io.ResourceLoader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import java.io.IOException;
import java.io.InputStream;

/**
 * @Author: 冰岩
 * @Date: 2023/07/05
 * @Description:
 */
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

    public XmlBeanDefinitionReader(BeanDefinitionRegistry beanDefinitionRegistry) {
        super(beanDefinitionRegistry);
    }

    public XmlBeanDefinitionReader(BeanDefinitionRegistry beanDefinitionRegistry, ResourceLoader resourceLoader) {
        super(beanDefinitionRegistry, resourceLoader);
    }

    @Override
    public void loadBeanDefinition(Resource resource) {
        try (InputStream inputStream = resource.getInputStream()) {
            doLoadBeanDefinition(inputStream);
        } catch (IOException | ClassNotFoundException e) {
            throw new BeansException("IOException or ClassNotFound when load xmlBeandefinition");
        }
    }

    private void doLoadBeanDefinition(InputStream inputStream) throws ClassNotFoundException {
        Document xmlDocument = XmlUtil.readXML(inputStream);
        Element root = xmlDocument.getDocumentElement();
        NodeList childNodes = root.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            if (!(childNodes.item(i) instanceof Element)) continue;
            if (!"bean".equals(childNodes.item(i).getNodeName())) continue;

            Element beanNode = (Element) childNodes.item(i);
            String id = beanNode.getAttribute("id");
            String name = beanNode.getAttribute("name");
            String className = beanNode.getAttribute("class");

            Class<?> clazz = Class.forName(className);
            String beanName = StrUtil.isNotEmpty(id) ? id : name;
            if (StrUtil.isEmpty(beanName)) {
                beanName = StrUtil.lowerFirst(clazz.getSimpleName());
            }

            BeanDefinition beanDefinition = new BeanDefinition(clazz);
            for (int j = 0; j < beanNode.getChildNodes().getLength(); j++) {
                if (!(beanNode.getChildNodes().item(j) instanceof Element)) {continue;}
                if (!"property".equals(beanNode.getChildNodes().item(i).getNodeName())) {continue;}
                // 解析标签：property
                Element property = (Element) beanNode.getChildNodes().item(j);
                String attrName = property.getAttribute("name");
                String attrValue = property.getAttribute("value");
                String attrRef = property.getAttribute("ref");
                Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;

                beanDefinition.getPropertyValues().addProperty(new PropertyValue(attrName, value));
            }
            if (getRegistry().containsBeanDefinition(beanName)) {
                throw new BeansException("beanName has existed:" + beanName);
            }
            getRegistry().registerBeanDefinition(beanName, beanDefinition);
        }
    }
}
